#include  <dirent.h>
#include  <fcntl.h>	
#include  <termios.h>		
#include  <errno.h>		
#include  <stdio.h>
#include  <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/sockios.h>
#include "canMsg.h"

#define MS_TO_TIMEVAL(x, y)    do {    \
        y.tv_sec  = x / 1000;          \
        y.tv_usec = (x % 1000) * 1000; \
} while (0)

typedef struct _T_BAUDRATE_INFO
{
    int iBaudrateName;
    int iBaudrateSpeed;
} T_BAUDRATE_INFO;

static T_BAUDRATE_INFO g_tBaudrateInfo[] = 
{
    {E_CAN_100K,  100000},
    {E_CAN_125K,  125000},
    {E_CAN_200K,  200000},
    {E_CAN_250K,  250000},
    {E_CAN_400K,  400000},
    {E_CAN_500K,  500000},
    {E_CAN_800K,  800000},
    {E_CAN_1000K, 1000000},
};

int CAN_Init(const char *pcCanName, E_CAN_BAUDRATE iBaudrateIndex, E_CAN_TYPE iCanType)
{
    int iCanFd = 0;
    struct sockaddr_can tCanAddr;
    struct ifreq ifr;
    int iRet = 0;
    int iSpeed = 0;
    int i = 0;
    char acCmd[64];
    
    if (NULL == pcCanName)
    {
        printf("Can init input param is NULL\n");
        return 0;
    }
    
    for(i = 0; i < sizeof(g_tBaudrateInfo)/sizeof(T_BAUDRATE_INFO); i++)
    {
        if (g_tBaudrateInfo[i].iBaudrateName == iBaudrateIndex)
        {
            iSpeed = g_tBaudrateInfo[i].iBaudrateSpeed;
        }	
    }
    
    sprintf(acCmd, "ip link set %s down", pcCanName);
    system(acCmd);
    usleep(1000);

	//can
	if(iCanType == E_CAN)
    	sprintf(acCmd, "ip link set %s type can bitrate %d", pcCanName, iSpeed);
	else	//can fd
		sprintf(acCmd, "ip link set %s type can bitrate %d dbitrate %d fd on", pcCanName, iSpeed, iSpeed);
		
    system(acCmd);
    usleep(1000);
    
    sprintf(acCmd, "ip link set %s up", pcCanName);
    system(acCmd);
    usleep(1000);

	//can fd 兼容can通信
//	if(iCanType == E_CAN_FD)
//	{
//		sprintf(acCmd, "ip link set %s down", pcCanName);
//	    system(acCmd);
//	    usleep(1000);
//
//		sprintf(acCmd, "ip link set %s type can bitrate %d", pcCanName, iSpeed);
//		system(acCmd);
//    	usleep(1000);
//
//		sprintf(acCmd, "ip link set %s up", pcCanName);
//		system(acCmd);
//		usleep(1000);
//	}
    
    iCanFd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    strcpy(ifr.ifr_name, pcCanName);
	/* 获取网络接口 */
    iRet = ioctl(iCanFd, SIOCGIFINDEX, &ifr);
    if (iRet < 0)
    {
       perror("can init:");
       close(iCanFd);
       return 0;
    }
    tCanAddr.can_family = AF_CAN;
    tCanAddr.can_ifindex = ifr.ifr_ifindex;
    
    bind(iCanFd, (struct sockaddr *)&tCanAddr, sizeof(tCanAddr));
    
    return iCanFd;
}

int CAN_SetFilter(int iCanfd, int iCanId)
{
	int iCanFdOn = 1;
	struct can_filter rfilter;

	if(iCanId > 0)
	{
       rfilter.can_id   = iCanId;

#ifdef CRCC
       rfilter.can_mask = CAN_EFF_MASK;
#endif

#ifdef RV_DEMON
        rfilter.can_mask = CAN_SFF_MASK;
#endif
        setsockopt(iCanfd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

	}
	else
	{
		/* To disable the reception of CAN frames on the selected CAN_RAW socket: */
		setsockopt(iCanfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);	
	}
	/* support canfd */
	setsockopt(iCanfd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &iCanFdOn, sizeof(iCanFdOn));
	
	return 0;
}

void CAN_Uninit(int iCanFd)
{
    if (iCanFd > 0)
    {
        close(iCanFd);
    }
}

int CAN_SendMsg(int iCanFd, T_CAN_MSG *ptCanMsg)
{
    struct can_frame tFrame;
    int iDataLen = 0;
    int iRet = 0;
    
    if ((iCanFd <= 0) || (NULL == ptCanMsg))
    {
       return 0;	
    }
    	
    memset(&tFrame, 0, sizeof(tFrame));
    if (ptCanMsg->cLen < 0)
    {
        iDataLen = 0;	
    }
    else if (ptCanMsg->cLen > 64)
    {
        iDataLen = 64;	
    }
    else
    {
        iDataLen = ptCanMsg->cLen;
    }
    
    tFrame.can_id = ptCanMsg->uiCanId;
    if (CAN_TYPE_EXTENDED == ptCanMsg->cIde)
    {
        tFrame.can_id &= CAN_EFF_MASK;
        tFrame.can_id |= CAN_EFF_FLAG;
    }
    else
    {
        tFrame.can_id &= CAN_SFF_MASK;
    }

	/* attention:canfd has no remote frames */
    if (CAN_FRAMETYPE_RTR == ptCanMsg->cRtr)
    {
        tFrame.can_id |= CAN_RTR_FLAG;
    }
    else
    {
        tFrame.can_id &= ~CAN_RTR_FLAG;
    }
    
    tFrame.can_dlc = iDataLen;

    if (iDataLen > 0)
    {
        memcpy(tFrame.data, ptCanMsg->acData, iDataLen);
    }
    
    iRet = write(iCanFd, &tFrame, sizeof(tFrame));
    
    //nbytes = sendto(sock_fd, &frame, sizeof(struct can_frame), 0, (struct sockaddr*)&addr, sizeof(addr));

    return iRet;
}

int CAN_RecvMsg(int iCanFd, T_CAN_MSG *ptCanMsg)
{
    struct can_frame tFrame;
    int iRet = 0;
    
    if ((iCanFd <= 0) || (NULL == ptCanMsg))
    {
       return 0;	
    }
    
    memset(&tFrame, 0, sizeof(tFrame));
    //iLen = recvfrom(iCanFd, &tFrame, sizeof(struct can_frame), 0, (struct sockaddr *)&addr, &len);
    iRet = read(iCanFd, &tFrame, sizeof(tFrame));
    if (iRet < 0)
    {
        return iRet;	
    }
    
    if (tFrame.can_id & CAN_EFF_FLAG)
    {
        ptCanMsg->cIde = CAN_TYPE_EXTENDED;
        ptCanMsg->uiCanId = tFrame.can_id & CAN_EFF_MASK;
    }
    else
    {
        ptCanMsg->cIde = CAN_TYPE_STANDARD;
        ptCanMsg->uiCanId = tFrame.can_id & CAN_SFF_MASK;
    }
    
    if (tFrame.can_id & CAN_RTR_FLAG)
    {
        ptCanMsg->cRtr = CAN_FRAMETYPE_RTR;
    }
    else
    {
        ptCanMsg->cRtr = CAN_FRAMETYPE_NORMAL;
    }
    
    ptCanMsg->cLen = tFrame.can_dlc;
    memcpy(ptCanMsg->acData, tFrame.data, tFrame.can_dlc);
    
    return iRet;
}

int CAN_RecvMsgTimeout(int iCanFd, T_CAN_MSG *ptCanMsg, int ms)
{
    struct can_frame tFrame;
    int iRet = 0;
	fd_set read_set;
	struct timeval tval;
    
    if ((iCanFd <= 0) || (NULL == ptCanMsg))
    {
       return -1;	
    }

	if (ms >= 0)//有超时时间
    {
        MS_TO_TIMEVAL(ms, tval);
    }

	while(1)
	{
		FD_ZERO(&read_set);
        FD_SET(iCanFd, &read_set);
        iRet = select(iCanFd + 1, &read_set, NULL, NULL,
                         (ms < 0) ? NULL : &tval);
        if (-1 == iRet)
        {        //select error
        	return -1;
        }
        else if (0 == iRet)
        {        //time out
        	return 0;
        }
        else
        {
            if (FD_ISSET(iCanFd, &read_set))
            {   
            	//接收到报文
            	memset(&tFrame, 0, sizeof(tFrame));
			    //iLen = recvfrom(iCanFd, &tFrame, sizeof(struct can_frame), 0, (struct sockaddr *)&addr, &len);
			    iRet = read(iCanFd, &tFrame, sizeof(tFrame));
			    if (iRet < 0)
			    {
			        return iRet;	
			    }
			    
			    if (tFrame.can_id & CAN_EFF_FLAG)
			    {
			        ptCanMsg->cIde = CAN_TYPE_EXTENDED;
                    ptCanMsg->uiCanId = tFrame.can_id & CAN_EFF_MASK;
			    }
			    else
			    {
			        ptCanMsg->cIde = CAN_TYPE_STANDARD;
                    ptCanMsg->uiCanId = tFrame.can_id & CAN_SFF_MASK;
			    }
			    
			    if (tFrame.can_id & CAN_RTR_FLAG)
			    {
			        ptCanMsg->cRtr = CAN_FRAMETYPE_RTR;
			    }
			    else
			    {
			        ptCanMsg->cRtr = CAN_FRAMETYPE_NORMAL;
			    }
			    
			    ptCanMsg->cLen = tFrame.can_dlc;
			    memcpy(ptCanMsg->acData, tFrame.data, tFrame.can_dlc);
				
				break;
            }
        }
	}
    
    return iRet;
}




